package info.openlvb.openface.server.ldap;

import info.openlvb.openface.client.base.Account;
import info.openlvb.openface.client.base.Group;
import info.openlvb.openface.client.base.Machine;
import info.openlvb.openface.server.log.FaceLog;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.List;
import java.util.Properties;

import javax.naming.Context;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import javax.naming.directory.BasicAttribute;
import javax.naming.directory.BasicAttributes;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;
import javax.naming.directory.ModificationItem;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;

public class LdapConnection {

	private static LdapConnection instance = null;
	private String LDAP_SERVER, GLOBAL_DC, ADMIN_DN, ADMIN_PWD;
	private String USERS_OU, GROUPS_OU, MACHINES_OU, SAMBA_DOMAIN;
	private Hashtable<String,String> ldapEnv;
	private DirContext ldapContext;
	private Properties prop;
	FaceLog log = FaceLog.getInstance();

	private LdapConnection(){
		log.message(log.INFO,"connexion au LDAP");
		prop = new Properties();
		try {
			FileInputStream in = new FileInputStream("ldap.properties");
			prop.load(in);
			in.close();
			LDAP_SERVER = prop.getProperty("ldap_server")+":"+prop.getProperty("ldap_port");
			GLOBAL_DC = prop.getProperty("ldap_global_dc");
			ADMIN_DN = prop.getProperty("ldap_admin_dn")+","+GLOBAL_DC;
			SAMBA_DOMAIN=prop.getProperty("samba_domain");
			ADMIN_PWD = prop.getProperty("ldap_admin_password");
			USERS_OU = prop.getProperty("ldap_users_ou");
			GROUPS_OU = prop.getProperty("ldap_group_ou");
			MACHINES_OU = prop.getProperty("ldap_machines_ou");
			log.message(log.INFO,LDAP_SERVER+"/"+GLOBAL_DC+"/"+ADMIN_DN+"/"+ADMIN_PWD);
			ldapEnv = new Hashtable<String,String>();
			ldapEnv.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
			ldapEnv.put(Context.PROVIDER_URL, "ldap://"+LDAP_SERVER);
			ldapEnv.put(Context.SECURITY_AUTHENTICATION,"simple");
			ldapEnv.put(Context.SECURITY_PRINCIPAL, ADMIN_DN);
			ldapEnv.put(Context.SECURITY_CREDENTIALS, ADMIN_PWD);
			ldapContext = new InitialDirContext(ldapEnv);

		} catch (FileNotFoundException e) {
			log.message(log.WARNING,"probleme de chargement de fichier - fichier non trouvé - de conf ldap");
			log.message(log.WARNING, FaceLog.printStackTrace(e));
		} catch (IOException e) {
			log.message(log.WARNING,"probleme de chargement de fichier de conf ldap : E/S");
			log.message(log.WARNING, FaceLog.printStackTrace(e));
		} catch (NamingException e) {
			log.message(log.WARNING,"prob de cnx au LDAP");
			log.message(log.WARNING, FaceLog.printStackTrace(e));
		}

	}
	public final static LdapConnection getInstance() {
		if(instance==null){
			instance = new LdapConnection(); 
			return instance;
		}else{
			return instance;
		}
	}
	
	/* uid : identifiant (ici guillaume.bordes = login)
	 * cn : nom de la personne
	 * givenname : prénom
	 * sn = nom + prenom
	 * gecos : description
	 */
	/**recherche dans l'annuaire LDAP un utilisateur par son uid
	 * 
	 * @param uid de l'utilisateur recherche
	 * 
	 * @return Account avec toutes les informations utilisateur
	 */
	public Account searchByUid(String uid){
		SearchControls controle = new SearchControls();
		String critere = "(uid="+uid+")";
		NamingEnumeration<SearchResult> e;
		try {
			e = ldapContext.search(USERS_OU+","+GLOBAL_DC, critere,controle);
			while(e.hasMore()){
				Account pers_cour = new Account();
				SearchResult r = e.next();
				try{
					/**Modification : Xavier
					 * Personnalisation par rapport à mon LDAP 
					 */
					//pers_cour.setPassword(r.getAttributes().get("sambaLMPassword").getAll().next().toString());
					pers_cour.setPassword(new String((byte[]) r.getAttributes().get("userPassword").get()));
					//pers_cour.setPassword(r.getAttributes().get("sambaLMPassword").getAll().next().toString());
					//pers_cour.setNom_complet(r.getAttributes().get("sn").getAll().next().toString());
					pers_cour.setLogin(r.getAttributes().get("uid").getAll().next().toString());
					pers_cour.setNom(r.getAttributes().get("cn").getAll().next().toString());
					//pers_cour.setPrenom(r.getAttributes().get("givenName").getAll().next().toString());
					pers_cour.setPrenom("prenom");
					//TODO : modifier par UserPassword !!
					//pers_cour.setDescription(r.getAttributes().get("gecos").getAll().next().toString());
					//System.out.println("userPassword"+r.getAttributes().get("userPassword").getAll().next().toString());
					//pers_cour.setPassword(r.getAttributes().get("userPassword").getAll().next().toString());
					return pers_cour;
				}catch(Exception ne){
					//MessageBox.alert("Un champs est manquant dans le compte utilisateur");
					log.message(log.WARNING, FaceLog.printStackTrace(ne));
				}
				return null;
			}
			return null;
		} catch (NamingException e1) {
			log.message(log.WARNING,"probleme searchByUid");
			log.message(log.WARNING, FaceLog.printStackTrace(e1));
		}
		return null;
	}

	/**
	 * recherche des utilisateurs appartenant à un groupe
	 * @author gbtux
	 * @param cn du groupe
	 * @return Group
	 * 
	 */
	public Group searchGroupByCn(String cn){

		SearchControls controle = new SearchControls();
		String critere = "(cn="+cn+")";
		NamingEnumeration<SearchResult> e;
		try {
			e = ldapContext.search(GROUPS_OU+","+GLOBAL_DC, critere,controle);
			while(e.hasMore()){
				Group group_cour = new Group();
				SearchResult r = e.next();
				group_cour.setCn(r.getAttributes().get("cn").getAll().next().toString());
				group_cour.setDescription(r.getAttributes().get("description").getAll().next().toString());
				group_cour.setDisplayname(r.getAttributes().get("displayName").getAll().next().toString());
				group_cour.setGid(r.getAttributes().get("gidNumber").getAll().next().toString());
				return group_cour;
			}
		} catch (NamingException e1) {
			log.message(log.WARNING, "probleme searchGroupByCn");
			log.message(log.WARNING, FaceLog.printStackTrace(e1));
		}

		return null;
	}
	/**
	 * recherche de tous les groupes dans le LDAP
	 * @author gbtux
	 * @param void
	 * @return liste des groupes
	 */
	public List<Group> searchGroups(){
		List<Group> lstgroup = new ArrayList<Group>();
		SearchControls controle = new SearchControls();
		String critere = "(cn=*)";
		NamingEnumeration<SearchResult> e;
		try {
			e = ldapContext.search(GROUPS_OU+","+GLOBAL_DC, critere,controle);
			while(e.hasMore()){
				Group group_cour = new Group();
				SearchResult r = e.next();
				group_cour.setCn(r.getAttributes().get("cn").getAll().next().toString());
				group_cour.setGid(r.getAttributes().get("gidNumber").getAll().next().toString());
				group_cour.setDescription(r.getAttributes().get("description").getAll().next().toString());
				try{
					Enumeration<?> values = r.getAttributes().get("memberUid").getAll();
					List<String> members = new ArrayList<String>();
					while(values.hasMoreElements()){
						members.add(values.nextElement().toString());
					}
					group_cour.setMembers((String[]) members.toArray());

				}catch(Exception e2){
					log.message(log.DEBUG, "pas de membre");
				}
				lstgroup.add(group_cour);
			}
			return lstgroup;
		} catch (NamingException e1) {
			log.message(log.WARNING, "probleme searchGroups");
			log.message(log.WARNING, FaceLog.printStackTrace(e1));
		}
		return null;
	}
	/**
	 * recherche de tous les membres d'un groupe
	 * @author gbtux
	 * @param cn du groupe
	 * @return 
	 */
	public List<Account> findMembersByCnOfGroup(String cn) {
		List<Account> lstpers = new ArrayList<Account>();
		SearchControls controle = new SearchControls();
		String critere = "(cn="+cn+")";
		NamingEnumeration<SearchResult> e;
		try {
			e = ldapContext.search(GROUPS_OU+","+GLOBAL_DC, critere,controle);
			while(e.hasMore()){
				SearchResult r = e.next();
				try{
					Enumeration<?> values = r.getAttributes().get("memberUid").getAll();
					while(values.hasMoreElements()){
						Account account_cour = searchByUid(values.nextElement().toString());
						account_cour.setGroupe_courant(cn);
						lstpers.add(account_cour);
					}

				}catch(Exception w){
					log.message(log.WARNING, "pas de members dans le groupe : "+cn);
					log.message(log.WARNING, FaceLog.printStackTrace(w));
				}
			}
			return lstpers;
		} catch (NamingException e1) {
			log.message(log.WARNING, "probleme searchGroups");
			log.message(log.WARNING, FaceLog.printStackTrace(e1));
		}
		return null;
	}

	/**
	 * ajout d'un nouveau groupe dans le LDAP
	 * @author gbtux
	 * @param Group
	 * @return void
	 */
	public void addGroup(Group group){
		String dn = "cn="+group.getCn()+","+GROUPS_OU+","+GLOBAL_DC;
		Attributes attributes = new BasicAttributes(true);

		Attribute attr_obj7 = new BasicAttribute("objectClass");
		attr_obj7.add("posixGroup");
		attributes.put(attr_obj7);
		Attribute attr_obj6 = new BasicAttribute("gidNumber");
		attr_obj6.add(nextgid()); 
		attributes.put(attr_obj6);
		Attribute attr_desc = new BasicAttribute("description");
		attr_desc.add(group.getDescription());
		attributes.put(attr_desc);

		try {
			ldapContext.createSubcontext(dn, attributes);
			BasicAttribute newAtt1 = new BasicAttribute("objectClass","sambaGroupMapping");
			BasicAttribute newAtt2 = new BasicAttribute("sambaGroupType","2");
			BasicAttribute newAtt3 = new BasicAttribute("sambaSID",getSID());
			BasicAttribute newAtt4 = new BasicAttribute("displayName",group.getCn());
			ModificationItem[] modItems = new ModificationItem[4];
			modItems[0] = new ModificationItem(DirContext.ADD_ATTRIBUTE,newAtt1);
			modItems[1] = new ModificationItem(DirContext.ADD_ATTRIBUTE,newAtt2);
			modItems[2] = new ModificationItem(DirContext.ADD_ATTRIBUTE,newAtt3);
			modItems[3] = new ModificationItem(DirContext.ADD_ATTRIBUTE,newAtt4);
			ldapContext.modifyAttributes(dn, modItems);

			ModificationItem[] modItemsMembers = new ModificationItem[group.getMembers().length];
			for(int i=0;i<group.getMembers().length;i++){
				Attribute attr_member = new BasicAttribute("memberUid");
				attr_member.add(group.getMembers()[i]);
				modItemsMembers[i] = new ModificationItem(DirContext.ADD_ATTRIBUTE,attr_member);
			}
			ldapContext.modifyAttributes(dn, modItemsMembers);
		} catch (NamingException e) {
			log.message(log.WARNING, "probleme addGroup");
			log.message(log.WARNING, FaceLog.printStackTrace(e));
		}
	}
	private String getSID() {
		String critere = "(sambaDomainName="+SAMBA_DOMAIN+")";
		SearchControls controle = new SearchControls();
		NamingEnumeration<SearchResult> e;
		String SID="";
		try {
			e = ldapContext.search(GLOBAL_DC, critere,controle);
			while(e.hasMore()){
				SearchResult r = e.next();
				SID = r.getAttributes().get("sambaSID").getAll().next().toString();
				String GID = r.getAttributes().get("gidNumber").getAll().next().toString();
				int intGID = Integer.parseInt(GID);
				intGID--;
				GID = String.valueOf(intGID);
				SID+="-"+GID;

				return SID;
			}
		}catch(Exception ex){
			log.message(log.WARNING, "probleme getSID");
			log.message(log.WARNING, FaceLog.printStackTrace(ex));
		}
		return null;
	}
	private String nextgid() {
		String critere = "(sambaDomainName="+SAMBA_DOMAIN+")";
		SearchControls controle = new SearchControls();
		NamingEnumeration<SearchResult> e;
		String nextgid="";
		try {
			e = ldapContext.search(GLOBAL_DC, critere,controle);
			while(e.hasMore()){
				SearchResult r = e.next();
				nextgid = r.getAttributes().get("gidNumber").getAll().next().toString();
			}
			incrementgid(nextgid);
			log.message(log.INFO, "nextgid : "+nextgid);
			return nextgid;
		}catch(Exception ex){
			log.message(log.WARNING, "probleme nexgid");
			log.message(log.WARNING, FaceLog.printStackTrace(ex));
		}
		return null;
	}
	private void incrementgid(String nextgid) {

		String dn = "sambaDomainName="+SAMBA_DOMAIN+","+GLOBAL_DC;
		int newgid = Integer.parseInt(nextgid);
		newgid++;
		BasicAttribute gidAtt = new BasicAttribute("gidNumber",String.valueOf(newgid));
		Attributes attributes = new BasicAttributes(true);
		attributes.put(gidAtt);
		try{
			ldapContext.modifyAttributes(dn, DirContext.REPLACE_ATTRIBUTE, attributes);
		}catch(Exception exc){
			log.message(log.WARNING, "probleme incrementation gidNumber");
			log.message(log.WARNING, FaceLog.printStackTrace(exc));
		}

	}
	public List<String> searchUsersUid(){
		SearchControls controle = new SearchControls();
		String critere = "(uid=*)";
		NamingEnumeration<SearchResult> e;
		try {
			e = ldapContext.search(USERS_OU+","+GLOBAL_DC, critere,controle);
			List<String> users = new ArrayList<String>();
			while(e.hasMore()){
				SearchResult r = e.next();
				users.add(r.getAttributes().get("uid").getAll().next().toString());
			}
			return users;
		}catch(Exception e1){
			log.message(log.WARNING, "probleme searchUsersUid");
			log.message(log.WARNING, FaceLog.printStackTrace(e1));
		}
		return null;
	}
	/**
	 * enleve un utilisateur comme membre d'un groupe
	 * @param cnOfGroup
	 * @param login
	 * @return void
	 * @author gbtux
	 */
	public void removeUserInGroup(String cnOfGroup, String login){
		String dn = "cn="+cnOfGroup+","+GROUPS_OU+","+GLOBAL_DC;
		BasicAttribute newAtt = new BasicAttribute("memberUid",login);
		ModificationItem[] modItems = new ModificationItem[1];
		modItems[0] = new ModificationItem(DirContext.REMOVE_ATTRIBUTE,newAtt);
		try {
			ldapContext.modifyAttributes(dn, modItems);
		} catch (NamingException e1) {
			log.message(log.WARNING, "probleme removeUserInGroup");
			log.message(log.WARNING, FaceLog.printStackTrace(e1));
		}
	}
	/**
	 * ajoute un utilisateur dans un groupe
	 * 
	 */
	public void addUserInGroup(String group, String userUid){
		String dn = "cn="+group+","+GROUPS_OU+","+GLOBAL_DC;
		ModificationItem[] modItemsMembers = new ModificationItem[1];
		Attribute attr_member = new BasicAttribute("memberUid");
		attr_member.add(userUid);
		//attr_member.add("nobody");
		modItemsMembers[0] = new ModificationItem(DirContext.ADD_ATTRIBUTE,attr_member);
		try {
			ldapContext.modifyAttributes(dn, modItemsMembers);
		} catch (NamingException e) {
			log.message(log.WARNING, "probleme addUserInGroup");
			log.message(log.WARNING, FaceLog.printStackTrace(e));
		}
	}
	/**
	 * suppression d'un groupe
	 */
	public void deleteGroup(String cnOfGroup){
		String dn = "cn="+cnOfGroup+","+GROUPS_OU+","+GLOBAL_DC;
		try {
			ldapContext.unbind(dn);
		} catch (NamingException e) {
			log.message(log.WARNING, "probleme deleteGroup");
			log.message(log.WARNING, FaceLog.printStackTrace(e));
		}
	}
	/**
	 * ajout d'un utilisateur
	 * TODO : si description == administrateur --> on modifie le groupe par défaut !! + ajout au groupe domain admin (512)
	 */
	public void addUser(Account account){
		String dn = "uid="+account.getLogin()+","+USERS_OU+","+GLOBAL_DC;
		Attributes attributes = new BasicAttributes(true);

		Attribute attr_obj7 = new BasicAttribute("objectClass");
		attr_obj7.add("inetOrgPerson"); //avant openlvb
		attributes.put(attr_obj7);

		Attribute attr_cn = new BasicAttribute("cn");
		attr_cn.add(account.getNom());
		attributes.put(attr_cn);

		Attribute attr_sn = new BasicAttribute("sn");
		attr_sn.add(account.getNom());
		attributes.put(attr_sn);

		Attribute attr_givenname = new BasicAttribute("givenName");
		attr_givenname.add(account.getPrenom());//
		attributes.put(attr_givenname);

		Attribute attr_uid = new BasicAttribute("uid");
		attr_uid.add(account.getLogin());
		attributes.put(attr_uid);

		Attribute attr_pass = new BasicAttribute("userPassword");
		SSHA ssha = new SSHA("SHA");
		attr_pass.add(ssha.createDigest(account.getPassword()));
		attributes.put(attr_pass);

		Attribute attr_mail = new BasicAttribute("mail");
		attr_mail.add(account.getMail());
		attributes.put(attr_mail);

		try {
			ldapContext.createSubcontext(dn, attributes);
			//partie à ne pas toucher
			//en effet, on ne peut ajouter en même temps les 2 objectclass openlvb 
			//(dérivé de inetOrgperson) et posixAccount
			BasicAttribute newAtt = new BasicAttribute("objectClass","posixAccount");
			ModificationItem[] modItems = new ModificationItem[6];
			modItems[0] = new ModificationItem(DirContext.ADD_ATTRIBUTE,newAtt);
			Attribute attr_shell = new BasicAttribute("loginShell");
			attr_shell.add(account.getShell());
			modItems[1] = new ModificationItem(DirContext.ADD_ATTRIBUTE,attr_shell);

			Attribute attr_gecos = new BasicAttribute("gecos");
			attr_gecos.add(account.getNom_complet());
			modItems[2] = new ModificationItem(DirContext.ADD_ATTRIBUTE,attr_gecos);

			Attribute attr_uid_number = new BasicAttribute("uidNumber");
			attr_uid_number.add(nextuid()); 
			modItems[3] = new ModificationItem(DirContext.ADD_ATTRIBUTE,attr_uid_number);

			Attribute attr_gid_number = new BasicAttribute("gidNumber");
			if(account.getDescription().equals("administrateur")){
				attr_gid_number.add("512");
			}else{
				attr_gid_number.add("513");
			}
			modItems[4] = new ModificationItem(DirContext.ADD_ATTRIBUTE,attr_gid_number);

			Attribute attr_home = new BasicAttribute("homeDirectory");
			attr_home.add("/home/openlvb/"+account.getLogin());
			modItems[5] = new ModificationItem(DirContext.ADD_ATTRIBUTE,attr_home);

			ldapContext.modifyAttributes(dn, modItems);
			//fin do not touch

		} catch (NamingException ne) {
			log.message(log.WARNING, "probleme addUser");
			log.message(log.WARNING, FaceLog.printStackTrace(ne));
		}
	}
	private String nextuid() {
		String critere = "(sambaDomainName="+SAMBA_DOMAIN+")";
		SearchControls controle = new SearchControls();
		NamingEnumeration<SearchResult> e;
		String nextuid="";
		try {
			e = ldapContext.search(GLOBAL_DC, critere,controle);
			while(e.hasMore()){
				SearchResult r = e.next();
				nextuid = r.getAttributes().get("uidNumber").getAll().next().toString();
			}
			incrementuid(nextuid);
			log.message(log.INFO, "nextgid : "+nextuid);
			return nextuid;
		}catch(Exception ex){
			log.message(log.WARNING, "probleme nextuid");
			log.message(log.WARNING, FaceLog.printStackTrace(ex));
		}
		return null;
	}
	private void incrementuid(String nextuid) {

		String dn = "sambaDomainName="+SAMBA_DOMAIN+","+GLOBAL_DC;
		int newuid = Integer.parseInt(nextuid);
		newuid++;
		BasicAttribute uidAtt = new BasicAttribute("uidNumber",String.valueOf(newuid));
		Attributes attributes = new BasicAttributes(true);
		attributes.put(uidAtt);
		try{
			ldapContext.modifyAttributes(dn, DirContext.REPLACE_ATTRIBUTE, attributes);
		}catch(Exception exc){
			log.message(log.WARNING, "probleme incrementation uidNumber");
			log.message(log.WARNING, FaceLog.printStackTrace(exc));
		}

	}
	/**
	 * modification d'un groupe
	 */
	public void modifyGroup(String oldcn, String name, String description){
		BasicAttribute descAtt = new BasicAttribute("description", description);
		BasicAttribute displayAtt = new BasicAttribute("displayName", name);
		Attributes attributes = new BasicAttributes(true);
		attributes.put(descAtt);
		attributes.put(displayAtt);

		if(oldcn.equals(name)){
			String dn = "cn="+oldcn+","+GROUPS_OU+","+GLOBAL_DC;
			try{
				ldapContext.modifyAttributes(dn, DirContext.REPLACE_ATTRIBUTE, attributes);
			}catch(Exception exc){
				log.message(log.WARNING, "probleme modifyGroup sans modif dn");
				log.message(log.WARNING, FaceLog.printStackTrace(exc));
			}
		}else{
			String olddn = "cn="+oldcn+","+GROUPS_OU+","+GLOBAL_DC;
			String newdn = "cn="+name+","+GROUPS_OU+","+GLOBAL_DC;
			try{
				ldapContext.rename(olddn, newdn);
				ldapContext.modifyAttributes(newdn, DirContext.REPLACE_ATTRIBUTE, attributes);
			}catch(Exception exc){
				log.message(log.WARNING, "probleme modifyGroup");
				log.message(log.WARNING, FaceLog.printStackTrace(exc));
			}
		}
	}
	/**
	 * recherche de tous les utilisateurs
	 */
	public List<Account> searchUsers(){
		List<Account> lstusers = new ArrayList<Account>();
		SearchControls controle = new SearchControls();
		String critere = "(uid=*)";
		NamingEnumeration<SearchResult> e;
		try {
			e = ldapContext.search(USERS_OU+","+GLOBAL_DC, critere,controle);
			while(e.hasMore()){
				SearchResult r = e.next();
				int uidNumber=Integer.parseInt(r.getAttributes().get("uidNumber").getAll().next().toString());
				if(uidNumber>=1000	&& uidNumber < 65000){
					Account cour = new Account();
					cour.setDescription(r.getAttributes().get("uid").getAll().next().toString());
					//ici on va chercher un des champs nécessaires a samba
					//si on trouve vrai
					cour.setSambaEnabled(false);
					//NamingEnumeration<?> objectclass = r.getAttributes().get("objectClass").getAll();
					/*while(objectclass.hasMore()){
						String objectC = (String) objectclass.next();
						if(objectC.equals("sambaSamAccount")){
							cour.setSambaEnabled(true);
							cour.setHome(r.getAttributes().get("homeDirectory").getAll().next().toString());
						}
					}*/
					cour.setHome(r.getAttributes().get("homeDirectory").getAll().next().toString());
					cour.setGroupe_principal(r.getAttributes().get("gidNumber").getAll().next().toString());
					cour.setLogin(r.getAttributes().get("uid").getAll().next().toString());
					try{
						cour.setMail(r.getAttributes().get("mail").getAll().next().toString());
					}catch(Exception en){
						cour.setMail("");
					}
					cour.setNom(r.getAttributes().get("cn").getAll().next().toString());
					cour.setNom_complet(r.getAttributes().get("gecos").getAll().next().toString());
					cour.setPassword(r.getAttributes().get("userPassword").getAll().next().toString());
					cour.setPrenom(r.getAttributes().get("givenName").getAll().next().toString());
					cour.setShell(r.getAttributes().get("loginShell").getAll().next().toString());
					lstusers.add(cour);
				}
			}
			return lstusers;
		}catch(Exception ex){
			log.message(log.WARNING, "probleme searchUsers");
			log.message(log.WARNING, FaceLog.printStackTrace(ex));
		}
		return null;
	}
	/**
	 * modification d'un utilisateur
	 * @author gbtux
	 * @param old_pseudo
	 * @param newlogin
	 * @param nom
	 * @param prenom
	 * @param mail
	 * @param repperso
	 */
	public void modifyAccount(String old_pseudo, String newlogin, String nom, String prenom, String mail, String repperso){
		BasicAttribute cnAtt = new BasicAttribute("cn", nom);
		BasicAttribute snAtt = new BasicAttribute("sn", nom);
		BasicAttribute prenomAtt = new BasicAttribute("givenName", prenom);
		Attributes attributes = new BasicAttributes(true);
		attributes.put(cnAtt);
		attributes.put(snAtt);
		attributes.put(prenomAtt);

		BasicAttribute mailAtt = new BasicAttribute("mail", mail);
		Attributes attributes2 = new BasicAttributes(true);
		attributes2.put(mailAtt);

		BasicAttribute homeAtt = new BasicAttribute("homeDirectory", repperso);
		Attributes attributes3 = new BasicAttributes(true);
		attributes3.put(homeAtt);

		if(old_pseudo.equals(newlogin)){
			String dn = "uid="+old_pseudo+","+USERS_OU+","+GLOBAL_DC;
			try{
				ldapContext.modifyAttributes(dn, DirContext.REPLACE_ATTRIBUTE, attributes);
				try{
					ldapContext.modifyAttributes(dn, DirContext.REPLACE_ATTRIBUTE, attributes2);
				}catch(Exception exc){
					ldapContext.modifyAttributes(dn, DirContext.ADD_ATTRIBUTE, attributes2);
				}
				try{
					ldapContext.modifyAttributes(dn, DirContext.REPLACE_ATTRIBUTE, attributes3);
				}catch(Exception exc){
					ldapContext.modifyAttributes(dn, DirContext.ADD_ATTRIBUTE, attributes3);
				}
			}catch(Exception exc){
				log.message(log.WARNING, "probleme modifyAccount sans modif dn");
				log.message(log.WARNING, FaceLog.printStackTrace(exc));
			}
		}else{
			//on modifie l'uid
			String olddn = "uid="+old_pseudo+","+USERS_OU+","+GLOBAL_DC;
			String newdn = "uid="+newlogin+","+USERS_OU+","+GLOBAL_DC;
			try{
				ldapContext.rename(olddn, newdn);
				ldapContext.modifyAttributes(newdn, DirContext.REPLACE_ATTRIBUTE, attributes);
			}catch(Exception exc){
				log.message(log.WARNING, "probleme modifyAccount");
				log.message(log.WARNING, FaceLog.printStackTrace(exc));
			}
		}



	}
	/**
	 * suppression d'un utilisateur à/p de son uid = prenom.nom
	 * @author gbtux
	 * @param uid
	 */
	public void deleteUser(String uid){
		String dn = "uid="+uid+","+USERS_OU+","+GLOBAL_DC;
		try {
			ldapContext.unbind(dn);
		} catch (NamingException e) {
			log.message(log.WARNING, "probleme deleteUser");
			log.message(log.WARNING, FaceLog.printStackTrace(e));
		}
	} 
	/**
	 * ajout d'une machine dans le ldap
	 * identifiée par son cn = nom de station
	 * gidNumber = 515 = groupe Domain Computers
	 * homeDirectory = obligatoire = /home/null
	 * objectClass = account (struct) / posixAccount / sambaSamAccount
	 * uidNumber = sambaNextRid de sambaDomainName (à incrémenter) 
	 * User Name = cn
	 * sambaSID = sambaSID de sambaDomainName + "-" + uidNumber*2+1000
	 * 
	 * soit la machine est en dhcp :
	 * 		-- on regarde le fichier de conf pour savoir si le dhcp est fermé ou non
	 * 		-- si fermé on ajoute la machine au dhcp + dns
	 * 		-- si pas fermé on ajoute rien
	 * soit la machine est en IP fixe est là on ajoute juste au DNS
	 */
	public void addMachine(String name, String desc){
		String dn = "uid="+name+"$,"+MACHINES_OU+","+GLOBAL_DC;
		Attributes attributes = new BasicAttributes(true);

		Attribute attr_obj2 = new BasicAttribute("objectClass");
		attr_obj2.add("account"); 
		attributes.put(attr_obj2);

		Attribute attr_obj9 = new BasicAttribute("uid");
		attr_obj9.add(name+"$"); 
		attributes.put(attr_obj9);
		try{
			ldapContext.createSubcontext(dn, attributes);
			ModificationItem[] modItems = new ModificationItem[10];

			Attribute attr_obj3 = new BasicAttribute("objectClass");
			attr_obj3.add("sambaSamAccount"); 
			modItems[0] = new ModificationItem(DirContext.ADD_ATTRIBUTE, attr_obj3);
			Attribute attr_obj10 = new BasicAttribute("objectClass");
			attr_obj10.add("posixAccount"); 
			modItems[1] = new ModificationItem(DirContext.ADD_ATTRIBUTE, attr_obj10);


			Attribute attr_obj4 = new BasicAttribute("cn");
			attr_obj4.add(name); 
			modItems[2] = new ModificationItem(DirContext.ADD_ATTRIBUTE, attr_obj4);

			Attribute attr_obj5 = new BasicAttribute("description");
			attr_obj5.add("Computer"); 
			modItems[3] = new ModificationItem(DirContext.ADD_ATTRIBUTE, attr_obj5);

			Attribute attr_obj6 = new BasicAttribute("gecos");
			attr_obj6.add("Computer"); 
			modItems[4] = new ModificationItem(DirContext.ADD_ATTRIBUTE, attr_obj6);

			Attribute attr_obj7 = new BasicAttribute("gidNumber");
			attr_obj7.add("515");
			modItems[5] = new ModificationItem(DirContext.ADD_ATTRIBUTE, attr_obj7);

			Attribute attr_obj8 = new BasicAttribute("homeDirectory");
			attr_obj8.add("/home/null");
			modItems[6] = new ModificationItem(DirContext.ADD_ATTRIBUTE, attr_obj8);

			Attribute attr_obj1 = new BasicAttribute("loginShell");
			attr_obj1.add("/home/null");
			modItems[7] = new ModificationItem(DirContext.ADD_ATTRIBUTE, attr_obj1);

			Attribute attr_obj11 = new BasicAttribute("uidNumber");
			String nextMUid = getNextMachineUid();
			attr_obj11.add(nextMUid);
			modItems[8] = new ModificationItem(DirContext.ADD_ATTRIBUTE, attr_obj11);

			Attribute attr_obj = new BasicAttribute("sambaSID");
			String nextSID = getNextMachineSID(nextMUid);
			attr_obj.add(nextSID);
			modItems[9] = new ModificationItem(DirContext.ADD_ATTRIBUTE, attr_obj);

			ldapContext.modifyAttributes(dn, modItems);

		}catch(Exception ex){
			log.message(log.WARNING, "probleme ajout machine");
			log.message(log.WARNING, FaceLog.printStackTrace(ex));

		}
	}
	/**
	 * @author gbtux
	 * @param machineuid
	 * @return
	 */
	private String getNextMachineSID(String machineuid) {
		String critere = "(sambaDomainName="+SAMBA_DOMAIN+")";
		SearchControls controle = new SearchControls();
		NamingEnumeration<SearchResult> e;
		String SID="";
		try {
			e = ldapContext.search(GLOBAL_DC, critere,controle);
			while(e.hasMore()){
				SearchResult r = e.next();
				SID = r.getAttributes().get("sambaSID").getAll().next().toString();
			}

			int calcSID = Integer.parseInt(machineuid);
			calcSID = calcSID * 2 + 1000; //algo de smbldapadd :)
			SID = SID + "-" + String.valueOf(calcSID);
			//System.out.println("SID :"+SID);
			return SID;
		}catch(Exception ex){
			log.message(log.WARNING, "probleme nextmachinesid");
			log.message(log.WARNING, FaceLog.printStackTrace(ex));
		}
		return null;
	}
	private String getNextMachineUid() {
		String critere = "(sambaDomainName="+SAMBA_DOMAIN+")";
		SearchControls controle = new SearchControls();
		NamingEnumeration<SearchResult> e;
		String nextuid="";
		try {
			e = ldapContext.search(GLOBAL_DC, critere,controle);
			while(e.hasMore()){
				SearchResult r = e.next();
				nextuid = r.getAttributes().get("sambaNextRid").getAll().next().toString();
			}
			String thenewuid = incrementmachineuid(nextuid);
			log.message(log.INFO, "nextmachineuid : "+nextuid);
			//System.out.println("nextuid"+nextuid);
			return thenewuid;
		}catch(Exception ex){
			log.message(log.WARNING, "probleme nextmachineuid");
			log.message(log.WARNING, FaceLog.printStackTrace(ex));
		}
		return null;
	}
	private String incrementmachineuid(String nextuid) {
		String dn = "sambaDomainName="+SAMBA_DOMAIN+","+GLOBAL_DC;
		int newuid = Integer.parseInt(nextuid);
		newuid++;
		BasicAttribute uidAtt = new BasicAttribute("sambaNextRid",String.valueOf(newuid));
		Attributes attributes = new BasicAttributes(true);
		attributes.put(uidAtt);
		try{
			ldapContext.modifyAttributes(dn, DirContext.REPLACE_ATTRIBUTE, attributes);
			return String.valueOf(newuid);
		}catch(Exception exc){
			log.message(log.WARNING, "probleme incrementation uidMachineNumber");
			log.message(log.WARNING, FaceLog.printStackTrace(exc));
		}
		return null;
	}
	public Machine searchMachineByUid(String uid){
		SearchControls controle = new SearchControls();
		uid = uid+"$";
		String critere = "(uid="+uid+")";
		NamingEnumeration<SearchResult> e;
		try {
			e = ldapContext.search(MACHINES_OU+","+GLOBAL_DC, critere,controle);
			while(e.hasMore()){
				Machine mac_cour = new Machine();
				SearchResult r = e.next();
				mac_cour.setUid(r.getAttributes().get("uid").getAll().next().toString());
				mac_cour.setDescription(r.getAttributes().get("description").getAll().next().toString());
				return mac_cour;
			}
		} catch (NamingException e1) {
			log.message(log.WARNING, "probleme searchMachineByUid");
			log.message(log.WARNING, FaceLog.printStackTrace(e1));
		}

		return null;
	}
	/**
	 * liste toutes les machines du LDAP
	 * @author gbtux
	 * @return List<Machine>
	 */
	public List<Machine> searchMachines(){
		List<Machine> lstmac = new ArrayList<Machine>();
		SearchControls controle = new SearchControls();
		String critere = "(uid=*)";
		NamingEnumeration<SearchResult> e;
		try {
			e = ldapContext.search(MACHINES_OU+","+GLOBAL_DC, critere,controle);
			while(e.hasMore()){
				Machine mac_cour = new Machine();
				SearchResult r = e.next();
				mac_cour.setUid(r.getAttributes().get("uid").getAll().next().toString());
				mac_cour.setDescription(r.getAttributes().get("description").getAll().next().toString());
				lstmac.add(mac_cour);
			}
			return lstmac;
		} catch (NamingException e1) {
			log.message(log.WARNING, "probleme searchMachines");
			log.message(log.WARNING, FaceLog.printStackTrace(e1));
		}
		return null;
	}
	
	public void modifyMachine(String old_uid, String new_uid, String description){
		BasicAttribute descAtt = new BasicAttribute("description", description);
		Attributes attributes = new BasicAttributes(true);
		attributes.put(descAtt);

		if(old_uid.equals(new_uid)){
			String dn = "uid="+old_uid+","+MACHINES_OU+","+GLOBAL_DC;
			try{
				ldapContext.modifyAttributes(dn, DirContext.REPLACE_ATTRIBUTE, attributes);
			}catch(Exception exc){
				log.message(log.WARNING, "probleme modifyMachine sans modif dn");
				log.message(log.WARNING, FaceLog.printStackTrace(exc));
			}
		}else{
			//on modifie l'uid
			String olddn = "uid="+old_uid+","+MACHINES_OU+","+GLOBAL_DC;
			String newdn = "uid="+new_uid+","+MACHINES_OU+","+GLOBAL_DC;
			try{
				ldapContext.rename(olddn, newdn);
				ldapContext.modifyAttributes(newdn, DirContext.REPLACE_ATTRIBUTE, attributes);
			}catch(Exception exc){
				log.message(log.WARNING, "probleme modifyMachine");
				log.message(log.WARNING, FaceLog.printStackTrace(exc));
			}
		}
	}
	/**
	 * @author gbtux
	 * suppression d'une machine dans le LDAP à/p de son uid
	 * @param uid
	 */
	public void deleteMachine(String uid){
		String dn = "uid="+uid+","+MACHINES_OU+","+GLOBAL_DC;
		try {
			ldapContext.unbind(dn);
		} catch (NamingException e) {
			log.message(log.WARNING, "probleme deleteMachine");
			log.message(log.WARNING, FaceLog.printStackTrace(e));
		}
	}
}
